#ifndef _NET80211_IEEE80211_PLM_H_
#define _NET80211_IEEE80211_PLM_H_

/* Bit mask for Mesh security configuration field in MSC ie */
#define IEEE80211_MSC_MAUTHENTICATOR	10000000
#define IEEE80211_MSC_CONNTOMKD			01000000
#define IEEE80211_MSC_DEFTROLENEGOT		00100000

/* PMK Length */
#define IEEE80211_PMK_LEN				16

/* PLM Action code */
#define PLM_ACTION_CATEGORY 		250
#define PLM_ACTION_CODE_OPEN		0
#define PLM_ACTION_CODE_CONFIRM 	1
#define PLM_ACTION_CODE_CLOSE		2

/* Key holder transport list code */
#define	MSA_KHT_NONE		0x00
#define	MSA_KHT_EAP			0x01

/* PLM FSM Timers */
#define IEEE80211_PLM_TOR1 			5 /* retry timer interval 5 (secs) */
#define IEEE80211_PLM_MAXRETRIES	3 /* max retries, TOR2 = TOR1 * MAXRETIES = 15 (secs) */
#define IEEE80211_PLM_TOC			5 /* confirm timer interval 5 (secs) */
#define IEEE80211_PLM_TOH			1 /* holding timer interval 1 (secs). */
									  /* since we don`t have a plm close implementation here, 
									  	holding interval should be as short as possible to allow 
									  	sm to jumo back to the INIT phasr instantly */
									  
/* MSA Reason code */
enum {
	MESH_SECURITY_FAILED_VERIFICATION	= 1,
	MESH_SECURITY_AUTHENTICATION_IMPOSSIBLE =2
};
	
/* global msa parameters */
struct ieee80211_msaparms {
	/* Local parameters */
	u_int8_t msa_handshakectl;	/* Handshake control */
	/* XXX: simply copy of corresponding rsn params? */
	u_int8_t msa_ucastcipher;	/* Selected pairwise cipher suite in msa ie */
	u_int8_t msa_keymgmt;	/* Selected key mgmt algo in msa ie*/
	u_int8_t msa_khtransport;	/* Key holder transport list in msa ie */

	u_int8_t msc_mkddid[IEEE80211_ADDR_LEN];
	u_int8_t msc_msecconf;	/* Mesh security configuration */

	u_int8_t msa_maid[IEEE80211_ADDR_LEN];	/* MA ID through role selection */
	u_int8_t msa_chosenpmk[IEEE80211_PMK_LEN];		/* chosen pmk through pmk selection */

	/* Peer parameters in received msa/msc ie */
	u_int8_t msa_phandshakectl;	/* Handshake control */
	u_int8_t msa_pucastcipher;	/* Selected pairwise cipher suite in msa ie */
	u_int8_t msa_pkeymgmt;	/* Selected key mgmt algo in msa ie*/
	u_int8_t msa_pkhtransport;	/* Key holder transport list in msa ie */

	u_int8_t msc_pmkddid[IEEE80211_ADDR_LEN];
	u_int8_t msc_pmsecconf;	/* Mesh security configuration in received msc ie */

	u_int8_t msa_pmaid[IEEE80211_ADDR_LEN];	/* MA ID in received msa ie */
	u_int8_t msa_pchosenpmk[IEEE80211_PMK_LEN];		/* chosen pmk in received msa ie */

	u_int8_t msa_isselector; /* result of selector selection, 1 for local and 0 for peer */
	int status_code;			/* status code or reason code used in plm confirm and close messages */

};

/* PLM FSM states */
enum ieee80211_plm_state {
	IEEE80211_PLM_S_IDLE = 0, 
	IEEE80211_PLM_S_LISTEN, 
	IEEE80211_PLM_S_OPN_SNT, 
	IEEE80211_PLM_S_CNF_RCVD,
	IEEE80211_PLM_S_OPN_RCVD, 
	IEEE80211_PLM_S_ESTAB, 
	IEEE80211_PLM_S_HOLDING
};

/* PLM FSM events */
enum ieee80211_plm_smevent {
	ACTOPN, PASOPN, CNCL, 
	OPN_ACPT, CNF_ACPT, CLS_ACPT, 
	OPN_RJCT, CNF_RJCT, 
	TOR1, TOR2, TOC, TOH
};

/* PLM FSM data */
struct ieee80211_plmsm {
	enum ieee80211_plm_state pstate;	/* previous state */
	enum ieee80211_plm_state cstate;	/* current state */
	struct timer_list retrytimer1; 		/* retry timer 1 - TOR1 */
	struct timer_list retrytimer2;		/* retry timer 2 - TOR2 */
	struct timer_list comfirmtimer; 	/* comfirm timer - TOC */
	struct timer_list holdingtimer;		/* holding timer - TOH */
	u_int8_t isselector;
};

/**
 * ieee80211_plm_openprocess - Process plm open message
 * @ni: global peer node data
 * @wh: header field of received message
 * @frm: beginning of processing data
 * @efrm: end of processing data
 * Returns: NULL on success
 */
void 
ieee80211_plm_openprocess(struct ieee80211_node *ni, struct ieee80211_frame *wh,
	u_int8_t *frm, u_int8_t *efrm, int rssi, u_int32_t rstamp);

/**
 * ieee80211_plm_confirmprocess - Process plm confirm message
 * @ni: global peer node data
 * @wh: header field of received message
 * @frm: beginning of processing data
 * @efrm: end of processing data
 * Returns: NULL on success
 */
void 
ieee80211_plm_confirmprocess(struct ieee80211_node *ni, struct ieee80211_frame *wh,
	u_int8_t *frm, u_int8_t *efrm);

/**
 * ieee80211_plm_closeprocess - Process plm close message
 * @ni: global peer node data
 * @wh: header field of received message
 * @frm: beginning of processing data
 * @efrm: end of processing data
 * Returns: NULL on success
 */
void 
ieee80211_plm_closeprocess(struct ieee80211_node *ni, struct ieee80211_frame *wh,
	u_int8_t *frm, u_int8_t *efrm);

/**
 * ieee80211_plm_opensent - sent a plm open message 
 * @ni: global peer node data
 * @skb: pointer to sk_buff structure to be passed to lower layer
 * @frm: pointer to the beginning of sk_buff data
 * @status: status code
 * Returns: 0 on success
 */
int 
ieee80211_plm_opensent(struct ieee80211_node * ni, 
	struct sk_buff *skb, u_int8_t *frm, int status);

/**
 * ieee80211_plm_confirmsent - sent a plm confirm message 
 * @ni: global peer node data
 * @skb: pointer to sk_buff structure to be passed to lower layer
 * @frm: pointer to the beginning of sk_buff data
 * @status: status code
 * Returns: 0 on success
 */
int 
ieee80211_plm_confirmsent(struct ieee80211_node * ni, 
	struct sk_buff *skb, u_int8_t *frm, int status);

/**
 * ieee80211_plm_closesent - sent a plm close message 
 * @ni: global peer node data
 * @skb: pointer to sk_buff structure to be passed to lower layer
 * @frm: pointer to the beginning of sk_buff data
 * @status: status code
 * Returns: 0 on success
 */
int 
ieee80211_plm_closesent(struct ieee80211_node * ni, 
	struct sk_buff *skb, u_int8_t *frm, int status);
/**
 * ieee80211_plm_smstep - push the plm state machine
 * @vap: global vap data
 * @sign: event signal
 * Returns: 0 on success
 */
int 
ieee80211_plm_smstep(struct ieee80211_node *ni, enum ieee80211_plm_smevent signal);

/**
 * ieee80211_plm_tor1handler - tor1 timeout handler
 * @arg: lone argument to the handler
 * Returns: NULL
 */
void 
ieee80211_plm_tor1handler(unsigned long arg);

/**
 * ieee80211_plm_tor2handler - tor1 timeout handler
 * @arg: lone argument to the handler
 * Returns: NULL
 */
void 
ieee80211_plm_tor2handler(unsigned long arg);

/**
 * ieee80211_plm_tochandler - tor1 timeout handler
 * @arg: lone argument to the handler
 * Returns: NULL
 */
void 
ieee80211_plm_tochandler(unsigned long arg);

/**
 * ieee80211_plm_tohhandler - tor1 timeout handler
 * @arg: lone argument to the handler
 * Returns: NULL
 */
void 
ieee80211_plm_tohhandler(unsigned long arg);

/**
 * ieee80211_plm_isselector - determine who is selector mp
 * called before plm process, communication peers calculate the selector then determine 
 * selected pairwise and key mgmt suite filled in msa ie. 
 * @peeraddr: peer mp's mac address
 * @localaddr: local mp's mac address
 * Returns: 1 - local is the selector, 0 - peer is the selector
 */
int 
ieee80211_plm_isselector(u_int8_t *peeraddr, u_int8_t *localaddr);



#endif
